#include <malloc.h>
#include <memory>
#include <stdio.h>

class Object {
public:
    Object()        { printf("ctor\n"); }
    ~Object()       { printf("dtor\n"); }
    void Set(int i) { i_ = i; }
    int Get()       { return i_; }

private:
    int i_;
};

class PrivateObject {
public:
    static std::unique_ptr<PrivateObject> Create(const char *message)
    {
        return std::unique_ptr<PrivateObject>(new PrivateObject(message));
    }

    ~PrivateObject()
    {
        printf("PrivateObject: %s\n", message_);
    }

private:
    PrivateObject(const char *message) : message_(message) {}
    const char *message_ = nullptr;
};

int main()
{
    printf("\nC style\n");
    {
        // 申请
        Object *ptr = (Object *)malloc(sizeof(*ptr));

        // 使用
        printf("value: %d, addr: %p\n", ptr->Get(), ptr);
        ptr->Set(30);
        printf("value: %d, addr: %p\n", ptr->Get(), ptr);

        // 释放
        free(ptr);
    }

    printf("\nC++ style\n");
    {
        // 申请
        Object *ptr = new Object();

        // 使用
        printf("value: %d, addr: %p\n", ptr->Get(), ptr);
        ptr->Set(30);
        printf("value: %d, addr: %p\n", ptr->Get(), ptr);

        // 释放
        delete ptr;
    }

    printf("\nunique_ptr\n");
    {
        // 申请
        std::unique_ptr<Object> ptr = std::make_unique<Object>();

        // 使用
        printf("value: %d, addr: %p\n", ptr->Get(), ptr.get());
        ptr->Set(30);
        printf("value: %d, addr: %p\n", ptr->Get(), ptr.get());

        // 转移
// #define ERROR
#ifdef ERROR
        std::unique_ptr<Object> ptr2 = ptr; // error
#else
        std::unique_ptr<Object> ptr2 = std::move(ptr);
#endif
        printf("addr: %p\n", ptr.get());
        printf("addr: %p\n", ptr2.get());
    }

    printf("\nshared_ptr\n");
    {
        std::shared_ptr<Object> ptr = std::make_shared<Object>();

        // 使用
        printf("value: %d, addr: %p\n", ptr->Get(), ptr.get());
        ptr->Set(30);
        printf("value: %d, addr: %p\n", ptr->Get(), ptr.get());

        // 复制
        std::shared_ptr<Object> ptr2 = ptr;
        printf("addr: %p\n", ptr.get());
        printf("addr: %p\n", ptr2.get());
    }

    {
        auto obj = PrivateObject::Create("private!");
    }
    return 0;
}
